import math
from dp.embeddings import GloveModel
from dp.parser import Parser
from datetime import datetime


def normalize_embedding(embedding):
    min_val = min(embedding)
    max_val = max(embedding)
    range_val = max_val - min_val
    return [(x - min_val) / range_val if range_val != 0 else 0.0 for x in embedding]


def digit_to_char(digit, base):
    return str(digit) if digit < 10 else chr(ord("A") + digit - 10)


# convert word embedding into integer
def radix_encode(vector, base=10):
    normalized = normalize_embedding(vector)
    encoded_str = []

    for val in normalized:
        scaled = val * base
        digit = min(base - 1, max(0, math.floor(scaled)))
        encoded_str.append(digit_to_char(digit, base))

    return int("".join(encoded_str), base) if base > 1 else 0


class Hasher:
    def __init__(self, model="glove-wiki-gigaword-50"):
        self.model: GloveModel = GloveModel(model)
        self.parser = Parser()

    def hash_query(self, sql):
        self.parser.query(sql)
        predicates = list(self.parser.get_embedding_predicate())

        embedding = []
        for i in predicates:
            if isinstance(i, str):
                embedding = [*embedding, *self.model.key(i)]
            else:
                embedding.append(i)
        # for sql query without from and where clause, provide default seed
        if not embedding:
            embedding = self.model.key("select")
        return radix_encode(embedding, 16)


if __name__ == "__main__":
    # demo
    word_vector = [0.34, -2.5, 1.78, 0.91, 0.888]  # word embedding
    integer_representation = radix_encode(word_vector, 16)
    print(integer_representation)

    hasher = Hasher()

    start = datetime.now()
    hashed = hasher.hash_query("select count(*), avg(*) from foo  ")
    print("time is ", (datetime.now() - start).microseconds)
    print(hashed)

    start = datetime.now()
    hashed = hasher.hash_query("select 1+1  ")
    print("time is ", (datetime.now() - start).microseconds)
    print(hashed)

    start = datetime.now()
    hashed = hasher.hash_query(
        "select count(*), avg(*) from foo where id=10 and age>20 and name='tom' "
    )
    print("time is ", (datetime.now() - start).microseconds)
    print(hashed)
